#include "proteinrenderer.h"
#include "../../datamanager/proteindatanode.h"
#include "proteinrendercontrol.h"
#include "../../mainwindow.h"

#ifdef WIN32
#include <windows.h>
#endif

#ifdef MACX_DEV
#include <gl.h>
#include <glu.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#endif

#include <glut.h>

using namespace PBVP;

ProteinRenderer::ProteinRenderer()
{
	m_ShowProtein = true;
	m_ShowAtoms = false;
	m_ShowBackbone = true;
	m_ShowRibbon = false;
	m_ShowBBox = true;
	// TODO
	m_pRendControl = new ProteinRenderControl(this);
}

ProteinRenderer::~ProteinRenderer()
{
	for(int i = 0; i < atoms.size(); i++) {
		delete atoms[i];
	}
	for(int i = 0; i < bonds.size(); i++) {
		delete bonds[i];
	}
}

void ProteinRenderer::initialize(MainInterface *mainInterface)
{
	RenderPlugin::initialize(mainInterface);
	// TODO
}

RenderPlugin* ProteinRenderer::clone()
{
	// TODO
	ProteinRenderer *pRenderer = new ProteinRenderer();
	return pRenderer;
}

void ProteinRenderer::begin()
{
	glPushAttrib(GL_ALL_ATTRIB_BITS);
	glEnable(GL_COLOR_MATERIAL);
	// TODO
}

void ProteinRenderer::end()
{
	glDisable(GL_COLOR_MATERIAL);
	glPopAttrib();
	// TODO
}

QWidget* ProteinRenderer::getRenderControl() const
{
	// TODO
	return m_pRendControl;
}

bool ProteinRenderer::initRender()
{
	// TODO
	return true;
}

bool ProteinRenderer::isSupported(DataInterface *pData) const
{
#ifdef __GNU__
	if(pData->getDataSetType() == PROTEIN_DATA) return true;
#else
	ProteinData *pProData = dynamic_cast<ProteinData *>(pData);
	if(pProData) return true;
#endif
	return false;
}

void ProteinRenderer::render(DataNode *pDataNode)
{
	glPushMatrix();
#ifdef __GNU__
	ProteinDataNode *pProNode = (ProteinDataNode *)(pDataNode);
#else
	ProteinDataNode *pProNode = dynamic_cast<ProteinDataNode *>(pDataNode);
	if(!pProNode) return;		// not a protein data
#endif
	m_pProtein = (ProteinData *)pProNode->data();

	if(m_ShowBBox) {
		pProNode->drawBoundingbox();
	}
	if(m_ShowProtein) {
		displayChains();
	}
	// TODO
	glPopMatrix();
}

void ProteinRenderer::reset()
{
	//TODO
}

void ProteinRenderer::displayChains()
{
	//glScalef(0.1f, 0.1f, 0.1f);
	// display atoms
	if(m_ShowAtoms) {
		QVector<Atom> atomList = m_pProtein->getAtoms();
		for(int i = 0; i < atomList.size(); i++) {
			glPushMatrix();
			Atom atom = atomList[i];
			glTranslatef(atom.position.x, atom.position.y, atom.position.z);
			glColor3f(atom.color.r, atom.color.g, atom.color.b);
			glutSolidSphere(atom.radius, 8, 5);
			glPopMatrix();
		}
	}

	// render ligand atoms
	std::vector<bool>& ligandVec = m_pRendControl->getLigandVector();
	for(int l = 0; l < ligandVec.size(); l++) {
		if(ligandVec[l]) {
			QVector<Atom> atomList = m_pProtein->getLigand(l)->getAtoms();
			for(int i = 0; i < atomList.size(); i++) {
				glPushMatrix();
				Atom atom = atomList[i];
				glTranslatef(atom.position.x, atom.position.y, atom.position.z);
				glColor3f(atom.color.r, atom.color.g, atom.color.b);
				glutSolidSphere(atom.radius, 8, 5);
				glPopMatrix();
			}
		}
	}

	if(m_ShowBackbone) {
		int nc = m_pProtein->numOfChains();
		for(int n = 0; n < nc; n++) {
			ChainData *pChain = m_pProtein->getChain(n);
			QList<Atom> backbone = pChain->getBackboneAtoms();
			glLineWidth(4);
			//glDisable(GL_LIGHTING);
			glColor3f(0.0f, 1.0f, 0.0f);
			glBegin(GL_LINE_STRIP);
			for(int i = 0; i < backbone.size(); i++) {
				Atom atom = backbone[i];
				glVertex3f(atom.position.x, atom.position.y, atom.position.z);
			}
			glEnd();
			// glEnable(GL_LIGHTING);
		}
	}
}

void ProteinRenderer::setDataNode(DataNode *pDataNode)
{
#ifdef __GNU__
	m_pProNode = (ProteinDataNode *)(pDataNode);
#else
	m_pProNode = dynamic_cast<ProteinDataNode *>(pDataNode);
#endif
	m_pProtein = (ProteinData *)m_pProNode->data();
	m_pRendControl->setChainSelect(m_pProtein->getChainNames());
	m_pRendControl->setLigandSelect(m_pProtein->getLigandNames());
}

//////////////////////////////////////////////////////////////////////////
// Public slots
//////////////////////////////////////////////////////////////////////////
void ProteinRenderer::updateView()
{
	//m_pMainWin->updateView();
	m_pProNode->updateView();
}

void ProteinRenderer::setShowProtein(int state)
{
	switch(state) {
	case Qt::Checked:
		m_ShowProtein = true;
		break;
	case Qt::Unchecked:
		m_ShowProtein = false;
		break;
	}
	updateView();
}

void ProteinRenderer::setShowAtoms(int state)
{
	switch(state) {
	case Qt::Checked:
		m_ShowAtoms = true;
		break;
	case Qt::Unchecked:
		m_ShowAtoms = false;
		break;
	}
	updateView();
}

void ProteinRenderer::setShowBackbone(int state)
{
	switch(state) {
	case Qt::Checked:
		m_ShowBackbone = true;
		break;
	case Qt::Unchecked:
		m_ShowBackbone = false;
		break;
	}
	updateView();
}

void ProteinRenderer::setShowBBox(int state)
{
	switch(state) {
	case Qt::Checked:
		m_ShowBBox = true;
		break;
	case Qt::Unchecked:
		m_ShowBBox = false;
		break;
	}
	updateView();
}

Q_EXPORT_PLUGIN2(proteinrenderer, ProteinRenderer)

